/*********************************************************************************
 *      Copyright:  (C) 2022 Li Yanting<liyanting2@163.com>
 *                  All rights reserved.
 *
 *       Filename:  convert.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(05/10/2022)
 *         Author:  Li Yanting <liyanting2@163.com>
 *      ChangeLog:  1, Release initial version on "05/10/2022 16:39:38"
 *                 
 ********************************************************************************/

#include "pdu.h"

int proc_ctr_num(char *ctr_num, char *ctr_num_buf, int buf_size)
{
    if( !ctr_num )
    {
        log_error("function: %s invalid parameter.\n", __func__);
        return -1;
    }

    char        head[8] = "0891";
    char        temp;
    int         i;

    /* remove character "+" */
    if( strcpy(ctr_num, &ctr_num[1]) < 0)
    {
        log_error("function %s remove character + failure.\n", __func__);
        return -2;
    }

    /* add character F at the tail */
    if( strcat(ctr_num, "F") < 0 )
    {
        log_error("function %s add character F at the tail failure.\n", __func__);
        return -3;
    }

    /* swap odd and even bits */
    for( i=0; i<=14; i+=2 )
    {
        temp = ctr_num[i];
        ctr_num[i] = ctr_num[i+1];
        ctr_num[i+1] = temp;
    }

    /* add head */

    if( snprintf(ctr_num_buf, buf_size, "%s%s", head, ctr_num) < 0)
    {
        log_error("function: %s add head failure.\n", __func__);
        return -4;
    }

    log_debug("function %s sms center number be handled: %s\n", __func__, ctr_num_buf);

    return 0;
}

int proc_num(char *num, char *num_buf, int buf_size)
{
    if( !num )
    {
        log_error("function: %s invalid parameter.\n", __func__);
        return -1;
    }

    int    i;
    char   temp;
    char   head[16] = "11000D91";
    char   tail[8] = "000800";

    /* remove character "+" */
    if( strcpy(num, &num[1]) < 0)
    {
        log_error("function %s remove character + failure.\n", __func__);
        return -2;
    }

    /* add character F at the tail */
    if( strcat(num, "F") < 0 )
    {
        log_error("function %s add character F at the tail failure.\n", __func__);
        return -3;
    }

    /* swap odd and even bits */
    for( i=0; i<=14; i+=2 )
    {
        temp = num[i];
        num[i] = num[i+1];
        num[i+1] = temp;
    }

    /* add head, tail */

    if( snprintf(num_buf, buf_size, "%s%s%s", head, num, tail) < 0 )
    {
        log_error("function: %s add head and tail failure.\n", __func__);
        return -4;
    }

    log_debug("function %s phone number be handled: %s\n", __func__, num_buf);

    return 0;
}

int utf8_to_unic(char *utf8, char *unic_buf, int *unic_len)
{
    if( !utf8 || !unic_buf )
    {
        log_error("function %s invalid parameter.\n", __func__);
        return -1;
    }

    char       *p_unic = unic_buf;
    char        b1, b2, b3, b4;

    while( *utf8 )
    {
        if( *utf8 > 0x00 && *utf8 <= 0x7E ) //(0xxxxxxx): 0xxx xxxx & 1000 0000(0x80) -> 0000 0000
        {
            *p_unic = 0;
            p_unic++;
            *p_unic = *utf8;
            p_unic++;
            utf8++;

            *unic_len+=2;
        }
        else if( (*utf8 & 0xE0) == 0xC0 ) //(110xxx xx 10xxxxxx); first: 110x xxxx & 1110 0000(0xE0) ->1100 0000(0xC0)
        {
            b1 = *utf8;
            b2 = *(utf8+1);

            *p_unic = (b1>>2) & 0x07;
            p_unic++;
            *p_unic = (b1<<6) + (b2 & 0x3F);
            p_unic++;
            utf8+=2;

            *unic_len+=2;
        }
        else if( (*utf8 & 0xF0) == 0xE0 ) //(1110 xxxx 10xxxx xx 10xxxxxx):1110 xxxx & 1111 0000(0xF0) -> 1110 0000(0xE0)
        {
            b1 = *utf8;
            b2 = *(utf8+1);
            b3 = *(utf8+2);

            *p_unic = (b1 << 4) + ((b2 >> 2) & 0x0F);
            p_unic++;
            *p_unic = (b2 << 6) + (b3 & 0x3F);
            p_unic++;
            utf8+=3;

            *unic_len+=2;
        }
        else if(((*utf8) & 0x1F) == 0x0F) //(11110xxx 10xxxxxx 10xxxxxx 10xxxxxx)
        {
            b1 = *utf8;
            b2 = *(utf8+1);
            b3 = *(utf8+2);
            b4 = *(unic_buf+3);

            *p_unic = ((b1<<2)&0x1C) + ((b2>>4)&0x03);
            p_unic++;
            *p_unic = (b2<<4) + ((b3>>2)&0x0F);
            p_unic++;
            *p_unic = (b3<<6) + (b4&0x3F);
            p_unic++;
            utf8+=4;

            *unic_len+=3;
        }
        else
        {
            log_error("function %s can not find utf8 data.\n", __func__);
            return -1;
        }
    }

    log_debug("unicode: \n");
    for(int i=0; i<*unic_len; i++)
    {
        log_debug("%02X ", unic_buf[i]);
    }
    log_debug("\n");

    return 0;
}

int hex_to_str(const char *hex, int hex_len, char *str_buf)
{
    if( !hex || !str_buf )
    {
        log_error("function %s invalid parameter.\n", __func__);
        return -1;
    }

    int               i;
    unsigned char     highbyte;
    unsigned char     lowbyte;

    for(i=0; i<hex_len; i++)
    {
        highbyte = hex[i] >> 4;
        lowbyte = hex[i] & 0x0f;
        highbyte += 0x30;
        if(highbyte <= 0x39)
            str_buf[i*2] = highbyte;
        else
            str_buf[i*2] = highbyte + 0x07;  
        lowbyte += 0x30;
        if(lowbyte <= 0x39)
            str_buf[i*2+1] = lowbyte;
        else
            str_buf[i*2+1] = lowbyte + 0x07;

    }
    
    log_debug("function %s byte to str: %s\n", __func__, str_buf);

    return 0;
}

int pdu_encode(char *utf8, char *ctr_num, char *num, char *pdu_buf, int buf_size, int *msg_len)
{
    if( !utf8 || !ctr_num || !num )
    {
        log_error("function %s invalid parameter.\n", __func__);
        return -1;
    }

    char    unicode_buf[MAX_UNIC_LEN] = {0};
    int     unic_len = 0;
    char    str_unicode_buf[MAX_UNIC_LEN*2] = {0};
    char    handle_buf[MAX_UNIC_LEN*2+2] = {0};
    char    handle_buf2[MAX_UNIC_LEN*2+34] = {0};
    char    sms_center_phone_buf[32] = {0};
    char    phone_number_buf[32] = {0};

    if( utf8_to_unic(utf8, unicode_buf, &unic_len) < 0 )
    {
        log_error("function %s UTF-8 to unicode failed, check your input.\n", __func__);
        return -2;
    }

    if( hex_to_str(unicode_buf, unic_len, str_unicode_buf) < 0 )
    {
        log_error("function %s byte to str failure.\n", __func__);
        return -3;
    }

    snprintf(handle_buf, sizeof(handle_buf)+1, "%02x%s", strlen(str_unicode_buf)/2, str_unicode_buf);

    proc_num(num, phone_number_buf, sizeof(phone_number_buf));
    snprintf(handle_buf2, sizeof(handle_buf2)+1, "%s%s", phone_number_buf, handle_buf);

   *msg_len = (int)strlen(handle_buf2)/2;

    proc_ctr_num(ctr_num, sms_center_phone_buf, sizeof(sms_center_phone_buf));
    snprintf(pdu_buf, buf_size+1, "%s%s", sms_center_phone_buf, handle_buf2);

    log_debug("funtion %s pdu convert successful! \npdu: %s\nmsg_len: %d\n", __func__, pdu_buf, *msg_len);

    return 0;
}

int tolower(int c) 
{ 
    if (c >= 'A' && c <= 'Z') 
    {
        return c + 'a' - 'A'; 
    } 
    else 
    { 
        return c; 
    } 
} 

int htoi(char *s) 
{ 
    int i; 
    int n = 0; 
    if (s[0] == '0' && (s[1]=='x' || s[1]=='X')) 
    { 
        i = 2; 
    } 
    else 
    { 
        i = 0; 
    } 
    for (; (s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z') || (s[i] >='A' && s[i] <= 'Z');++i) 
    { 
        if (tolower(s[i]) > '9') 
        { 
            n = 16 * n + (10 + tolower(s[i]) - 'a'); 
        } 
        else 
        { 
            n = 16 * n + (tolower(s[i]) - '0'); 
        } 
    } 
    return n;
}

int str_to_hex(const char *str,  char *hex_buf)
{
    if( !hex_buf || !str )
    {
        printf("function %s invalid parameter.\n", __func__);
        return -1;
    }

    int               i;
    unsigned char     highbyte;         
    unsigned char     lowbyte;           

    for(i=0; i<strlen(str)/2; i++)
    {
        highbyte = toupper(str[i*2]);   
        lowbyte = toupper(str[i*2+1]);

        if(highbyte <= 0x39)            
            highbyte -= 0x30;
        else                            
            highbyte -= 0x37;

        if(lowbyte <= 0x39)
            lowbyte -= 0x30;
        else
            lowbyte -= 0x37;

        hex_buf[i] = (highbyte << 4) | lowbyte;
        
        log_debug("%02X ", hex_buf[i]);
    }
    log_debug("\n");

    return 0;
}

int bit7_to_unic(char* bit7, char* unic_buf, int *unic_len)
{
    if(!bit7 || !unic_buf || !unic_len)
    {
        printf("%s Invalid parameter\n", __func__);
        return -1;
    }

    int nsrc = 0;       
    int ndst = 0;      
    int nbyte = 0;
    unsigned char nleft = 0;
    while(nsrc < strlen(bit7))
    {
        *unic_buf = ((*bit7 << nbyte) | nleft) & 0x7f;
        nleft = *bit7 >> (7-nbyte);
        unic_buf++;
        ndst++;
        nbyte++;
        if(nbyte == 7)
        {
            *unic_buf = nleft;
            unic_buf++;
            ndst++;
            nbyte = 0;
            nleft = 0;
        }
        bit7++;
        nsrc++;
    }
    *unic_buf = 0;
    *unic_len = ndst;

    log_debug("unic_len: %d\n", *unic_len);
    for(int i=0; i<*unic_len; i++)
    {
        log_debug("%02X ", unic_buf[i]);
    }
    log_debug("\n");

    return 0;
}

int pdu_decode(char *recv, char *num_buf, char *ctr_num_buf, char *time_buf, char *utf8_buf) //phone_numb:32; time:32; cent_numb:32; utf8_sms: 512
{
    int           i = 0;
    char          temp;
    
    char         *p_f = recv+24;
    char          f[64] = {0};

    int           num_len = 0;
    char          str_num_len[4] = {0};
    char         *p_num_len = recv+20;
    char          num_type[4] = {0};
    char         *p_num_type = recv+22;
    int           head_len = 0;

    char         *p_recv = recv;
    char          head[128] = {0};
    char         *p_head = head;
    char          ctr_num[16] = {0};
    char          time[32] = {0};
    char          num[30] = {0};
    char          sms_type[4] = {0};
    char         *p_time = time;
    int           bit7_to_unic_len = 0;

    // char                 sms_num_b[32] = {0};
    // char                 ctr_num_b[32] = {0};
    // char                 time_b[32] = {0};
    // char                 utf8_b[512] = {0};

    /* iconv() */
    iconv_t      cd;
    char         unic_buf[MAX_UNIC_LEN] = {0};
    char         *p_unic_start = unic_buf;
    int          unic_len = MAX_UNIC_LEN;
    char         utf8[512] = {0};
    char         *p_utf8 = utf8;
    int          utf8_size = sizeof(utf8);

    memcpy(str_num_len, p_num_len, 2);
    log_debug("str num len: %s\n", str_num_len);
    num_len = htoi(str_num_len);
    log_debug("num len: %d\n", num_len);

    
    memcpy(f, p_f, (num_len+20));
    if( strstr(f, "F") )
    {
        head_len = 45+num_len;
    }
    else
    {
        head_len = 44+num_len;
    }

    memcpy(num_type, p_num_type, 2);

    for(i=0; i<head_len/2; i++)
    {
        temp = *p_recv;
        *p_recv = *(p_recv+1);
        *(p_recv+1) = temp;
        p_recv+=2;
    }

    log_debug("head len: %d\n", head_len);
    memcpy(head, recv, head_len);
    log_debug("head: %s\n", head);

    memcpy(time, (p_head+(head_len-16)), 12);
    sprintf(time_buf, "%c%c-%c%c-%c%c %c%c:%c%c:%c%c", \
        *p_time, *(p_time+1), *(p_time+2), *(p_time+3), *(p_time+4), *(p_time+5), \
        *(p_time+6), *(p_time+7), *(p_time+8), *(p_time+9), *(p_time+10), *(p_time+11));
    log_debug("time: %s\n", time_buf);

    memcpy(ctr_num, (p_head+4), 13);
    sprintf(ctr_num_buf, "+%s", ctr_num);
    log_debug("center number: %s\n", ctr_num);

    memcpy(num, (p_head+24), num_len);
    sprintf(num_buf, "+%s", num);
    log_debug("number: %s\n", num);

    memcpy(sms_type, (p_head+head_len-18), 2);
    log_debug("sms type: %s\n", sms_type);

    if( strcmp(sms_type, "00") == 0)
    {
        bit7_to_unic(p_recv, unic_buf, &bit7_to_unic_len);
        for( i=0; i<bit7_to_unic_len; i+=2)
        {
            temp = unic_buf[i];
            unic_buf[i] = unic_buf[i+1];
            unic_buf[i+1] = temp;
        }
    }
    else
    {
        str_to_hex(p_recv, unic_buf);
        for( i=0; i<(strlen(recv)-head_len)/2; i+=2)
        {
            temp = unic_buf[i];
            unic_buf[i] = unic_buf[i+1];
            unic_buf[i+1] = temp;
        }
    }

    cd = iconv_open("UTF-8", "UNICODE");
    if(cd < 0)
    {
        log_error("function %s iconv_open failed.\n", __func__);
        return -1;
    }

    if( iconv(cd, &p_unic_start, (size_t *)&unic_len, &p_utf8, (size_t *)&utf8_size) < 0)
    {
        log_error("iconv failed\n");
        return -2;
    }

    iconv_close(cd);

    strcpy(utf8_buf, utf8);
    log_debug("utf-8: %s\n", utf8);

    return 0;
}


